package com.ft.scan.service.impl;

import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ft.scan.common.AliOSSUtils;
import com.ft.scan.common.ApiUrls;
import com.ft.scan.common.TextInResult;
import com.ft.scan.config.ApiConfig;
import com.ft.scan.domain.File;
import com.ft.scan.mapper.TextInMapper;
import com.ft.scan.service.ITextInService;
import okhttp3.*;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Service
public class TextInServiceImpl implements ITextInService {
    
    @Autowired
    final ApiConfig apiConfig = new ApiConfig();
    @Autowired
    TextInMapper textInMapper;

    HttpURLConnection connection;

    @NotNull
    private static HttpURLConnection getHttpURLConnection(String url, String appId, String secretCode, String Method) throws IOException {
        URL realUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
        conn.setRequestProperty("connection", "Keep-Alive");
        conn.setRequestProperty("Content-Type", "application/octet-stream");
        conn.setRequestProperty("x-ti-app-id", appId);
        conn.setRequestProperty("x-ti-secret-code", secretCode);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setRequestMethod(Method); // 设置请求方式
        return conn;
    }


    // 证件分类
    @Override
    public TextInResult cert_classify(byte[] imgData) {
        String url = ApiUrls.getUrlByApiName("CERT_CLASS");
        String appId = apiConfig.getAccessKey();
        String secretCode = apiConfig.getSecretKey();
        BufferedReader in = null;
        DataOutputStream out = null;
        String result = "";
        String Method = "POST"; // 设置请求方式

        try {
            connection = getHttpURLConnection(url, appId, secretCode, Method);
            out = new DataOutputStream(connection.getOutputStream());
            out.write(imgData);
            out.flush();
            out.close();

            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                // 请求成功
                in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
                // 获取数据中的内容
                JsonNode json_result = new ObjectMapper().readValue(result, JsonNode.class);
                // 获取数据中的code
                int code = json_result.get("code").asInt();
                //如果可以检测到是什么类型的证件
                if (code == 200) {
                    //获取英文类型
                    String type = json_result.get("result").get("type").asText();
                    //获取中文类型
                    String type_description = json_result.get("result").get("type_description").asText();

                    // 创建包含中文类型的 JSON 对象
                    ObjectNode responseJson = new ObjectMapper().createObjectNode();
                    responseJson.put("type_description", type_description);

                    TreeNode jsonNode = this.identifyCert(imgData, type);
                    return TextInResult.ok(String.valueOf(jsonNode));
                }
                String message = json_result.get("message").asText();
                return TextInResult.fail(code, message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return TextInResult.fail(666, "发送 POST 请求出现异常");
    }

    //身份证识别
    public JsonNode identifyCert(byte[] imgData, String classify) {
        String url = ApiUrls.getApiUrlByType(classify);
        String appId = apiConfig.getAccessKey();
        String secretCode = apiConfig.getSecretKey();
        BufferedReader in = null;
        DataOutputStream out = null;
        String result = "";
        String Method = "POST"; // 设置请求方式

        try {
            connection = getHttpURLConnection(url, appId, secretCode, Method);
            out = new DataOutputStream(connection.getOutputStream());
            out.write(imgData);
            out.flush();
            out.close();
            JsonNode json_result = null;
            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                // 请求成功
                in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
                // 获取数据中的内容
                json_result = new ObjectMapper().readValue(result, JsonNode.class);
                String type_description = null;
                //获取中文类型
                switch (classify) {
                    case "id_card": {
                        type_description = json_result.get("result").get("type_description").asText();
                        break;
                    }
                    case "family_register": {
                        type_description = "户口本";
                        break;
                    }
                    case "marriage_certificate": {
                        type_description = "结婚证";
                        break;
                    }
                    case "drive_license": {
                        type_description = "驾驶证";
                        break;
                    }
                }

                ArrayNode itemListNode = (ArrayNode) json_result.get("result").get("item_list");

                // 创建包含中文类型的 JSON 对象
                ObjectNode responseJson = new ObjectMapper().createObjectNode();
                //responseJson.put("item_list", itemListNode);
                responseJson.put("type_description", type_description);

                // 遍历itemListNode数组
                for (JsonNode node : itemListNode) {

                    // 获取当前元素的描述和值
                    String description = node.get("description").asText();
                    String value = node.get("value").asText();

                    responseJson.put(description, value);
                }

                // 返回包含中文类型的 JSON 对象
                return responseJson;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    //提取信息
    @Override
    public TextInResult contents_extract(String base64File, String keys, String type) {
        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES)) // 设置连接保持活动时间为 5 分钟
                    .build();

            MediaType mediaType = MediaType.parse("application/json");

            // 创建一个空的 JSONObject 对象
            JSONObject requestBodyData = new JSONObject();
            // 将字符串数组转换为 JSONArray 对象
            JSONArray keysArray = new JSONArray();
            // 将字符串拆分为字符串数组
            String[] keyList = keys.split(",");

            for (String str : keyList) {
                keysArray.put(str);
            }
            requestBodyData.put("keys", keysArray);
            requestBodyData.put("file", base64File);
            requestBodyData.put("type", type);


            // 将 JSONObject 对象转换成符合 JSON 格式的字符串
            String requestBodyString = requestBodyData.toString();

            // 使用请求体字符串创建 RequestBody 对象
            RequestBody body = RequestBody.create(mediaType, requestBodyString);

            Request request = new Request.Builder()
                    .url(ApiUrls.getUrlByApiName("NLP"))
                    .method("POST", body)
                    .addHeader("x-ti-app-id", apiConfig.getAccessKey())
                    .addHeader("x-ti-secret-code", apiConfig.getSecretKey())
                    .addHeader("Content-Type", "application/json")
                    .build();
            Response response = client.newCall(request).execute();

            ObjectMapper mapper = new ObjectMapper();   //创建 ObjectMapper 实例
            if (response.isSuccessful()) {
                // 使用 Jackson 的 JsonNode 来处理 JSON 数据
                JsonNode jsonResponse = mapper.readTree(response.body().byteStream());
                // 提取 "result" 字段对应的值
                JsonNode resultNode = jsonResponse.get("result");   //用get方法可以不考虑异常

                if (resultNode == null) {
                    return TextInResult.fail(jsonResponse.get("code").asInt(), String.valueOf(jsonResponse.get("message")));
                }
                // 提取 "item_list" 字段对应的值
                JsonNode item_listNode = resultNode.path("item_list");  //用path方法可以不考虑异常，为空时是一个空数组对象
                // 解析并返回处理后的结果
                return TextInResult.ok(item_listNode);
            } else {
                // 处理请求失败的情况
                // 可以根据具体需求抛出自定义异常或记录日志等
                System.out.println("错误的请求码: " + response.code());
                return TextInResult.fail(666, "错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            // 处理异常情况
            return TextInResult.fail(666, "错误");
        }

    }

    @Override
    public TextInResult scan_book(String[] images, String keys) {
        try {
            // 创建Word文档,并设置纸张的大小
            XWPFDocument doc = new XWPFDocument();

            for (int i = 0; i < images.length; i++) {
                // 解码Base64数据
                byte[] decodedBytes = Base64.getDecoder().decode(images[i]);

                // 创建一个ByteArrayInputStream对象
                ByteArrayInputStream inputStream = new ByteArrayInputStream(decodedBytes);

                // 获取图片的名称
                String imageName = i + ".png";

                // 创建一个MultipartFile对象
                MultipartFile multipartFile = new MockMultipartFile(imageName, imageName, "image/png", inputStream);

                // 将图片保存到临时目录
                String tempImageUrl = "example/" + imageName;
                // 保存图片
                java.io.File file = new java.io.File(tempImageUrl);
                // 创建文件夹
                if (!file.exists()) {
                    // 保存图片
                    multipartFile.transferTo(file);
                }
                // 创建段落
                XWPFParagraph paragraph = doc.createParagraph();
                // 添加图片到段落
                FileInputStream fis = new FileInputStream(tempImageUrl);
                BufferedImage bimg = ImageIO.read(fis);
                int originalWidth = bimg.getWidth();
                int originalHeight = bimg.getHeight();
                // 计算图片新的宽度和高度，使其宽度正好填满页宽，并保持比例不变
                int documentWidth = 480; // A4纸张宽度，单位为磅
                int newWidth = documentWidth - 72; // 留出页边距，单位为磅
                int newHeight = (int) (originalHeight * ((double) newWidth / originalWidth));
                fis.close();
                FileInputStream fi = new FileInputStream(tempImageUrl);
                paragraph.createRun().addPicture(fi, org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG, tempImageUrl, Units.toEMU(newWidth), Units.toEMU(newHeight));
                fi.close();
            }

            //临时文件存储位置
            String doc_path = "example/书本.docx";

            // 保存文档
            FileOutputStream fos = new FileOutputStream(doc_path);
            doc.write(fos);
            fos.close();

            // 读取文档内容变成base64字符串
            Path path = Paths.get(doc_path);
            byte[] fileContent = Files.readAllBytes(path);
            // 将文档内容转换为Base64字符串
            String base64String = Base64.getEncoder().encodeToString(fileContent);

            return contents_extract(base64String, keys, "word");
        } catch (Exception e) {
            e.printStackTrace();
            return TextInResult.fail(666, "扫描书本失败");
        }
    }

    private TextInResult pdfDeal(String apiName, byte[] pdfData, String type, Long userId) {
        String url = ApiUrls.getUrlByApiName(apiName);
        String appId = apiConfig.getAccessKey();
        String secretCode = apiConfig.getSecretKey();
        BufferedReader in = null;
        DataOutputStream out = null;
        String result = "";
        try {
            connection = getHttpURLConnection(url, appId, secretCode, "POST");
            out = new DataOutputStream(connection.getOutputStream());
            out.write(pdfData);
            out.flush();
            out.close();
            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }

                JsonNode jsonResult = new ObjectMapper().readValue(result, JsonNode.class);
                int code = jsonResult.get("code").asInt();
                if (code == 200) {
                    JsonNode resultJson = jsonResult.get("result");
                    String resultData = null;
                    try {
                        if (type == "docx") {
                            resultData = resultJson.get(type).asText();
                        } else if (type == "xlsx") {
                            resultData = resultJson.get("excel").asText();
                        } else resultData = resultJson.asText();
                        byte[] resultDataBytes = Base64.getDecoder().decode(resultData);
                        String filename = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + "(" + apiName + ")." + type;
                        String FileUrl = AliOSSUtils.uploadFileToOSS(filename, resultDataBytes);
                        return this.insertFile(filename, userId, FileUrl) == 1 ? TextInResult.ok(FileUrl) :
                                TextInResult.fail(666, "文件存储失败");
                    } catch (Exception e) {
                        return TextInResult.fail(code, "上传文件到阿里云OSS失败");
                    }
                }
                String message = jsonResult.get("message").asText();
                return TextInResult.fail(code, message);
            } else {
                return TextInResult.fail(responseCode, "请求失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return TextInResult.fail(666, "发送POST请求失败");
    }

    @Override
    public TextInResult pdfToWord(byte[] pdfData, Long userId) {
        return pdfDeal("PDF_TO_WORD", pdfData, "docx", userId);
    }

    @Override
    public TextInResult pdfToExcel(byte[] pdfData, Long userId) {
        return pdfDeal("PDF_TO_EXCEL", pdfData, "xlsx", userId);
    }

    @Override
    public TextInResult pdfToPPT(byte[] pdfData, Long userId) {
        return pdfDeal("PDF_TO_PPT", pdfData, "pptx", userId);
    }

    @Override
    public TextInResult pdfToJPG(byte[] pdfData, Long userId) {
        return pdfDeal("PDF_TO_JPG", pdfData, "zip", userId);
    }

    @Override
    public TextInResult wordToPDF(byte[] wordData, Long userId) {
        return pdfDeal("WORD_TO_PDF", wordData, "pdf", userId);
    }

    @Override
    public TextInResult excelToPdf(byte[] pdfData, Long userId) {
        return pdfDeal("EXCEL_TO_PDF", pdfData, "pdf", userId);
    }


    // 图片转word
    public TextInResult photo_to_word(byte[] imgData, Long userId) {
        return pdfDeal("PHOTO_TO_WORD", imgData, "docx", userId);
    }

    @Override
    public TextInResult wordToImg(byte[] pdfData, Long userId) {
        return pdfDeal("WORD_TO_IMAGE", pdfData, "zip", userId);
    }

    // 图片表格识别
    @Override
    public TextInResult photo_to_excel(byte[] imgData, Long userId) {
        return pdfDeal("PHOTO_TO_EXCEL", imgData, "xlsx", userId);
    }

    public TextInResult scanDeal(byte[] scanData, String type) {
        String appId = apiConfig.getAccessKey();
        String secretCode = apiConfig.getSecretKey();
        BufferedReader in = null;
        DataOutputStream out = null;
        String result = "";

        try {
            connection = getHttpURLConnection(ApiUrls.getUrlByApiName(type), appId, secretCode, "POST");
            out = new DataOutputStream(connection.getOutputStream());
            out.write(scanData);
            out.flush();
            out.close();
            int responseCode = connection.getResponseCode();
            if (responseCode == 200) {
                in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
                JsonNode jsonResult = new ObjectMapper().readValue(result, JsonNode.class);
                int code = jsonResult.get("code").asInt();
                return code == 200 ? TextInResult.ok(jsonResult.get("result").get("item_list")) :
                        TextInResult.fail(code, jsonResult.get("message").asText());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return TextInResult.fail(666, "POST请求发送失败");
    }

    private int insertFile(String filename, Long userId, String fileUrl) {
        File file = new File();
        file.setFilename(filename);
        file.setUserId(userId);
        file.setFileUrl(fileUrl);
        return textInMapper.insertFile(file);
    }

    @Override
    public List<File> selectHistoryFile(Long userId) {
        return textInMapper.getFileByUserId(Math.toIntExact(userId));
    }

    @Override
    public TextInResult photoToPdf(List<String> images, Long userId) {
        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(20, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES))
                    .build();
            MediaType mediaType = MediaType.parse("application/json");
            JSONObject requestBodyData = new JSONObject();
            JSONArray imageArray = new JSONArray();
            for (String image : images) {
                imageArray.put(image);
            }
            requestBodyData.put("files", imageArray);

            String requestBodyDataString = requestBodyData.toString();

            RequestBody requestBody = RequestBody.create(mediaType, requestBodyDataString);
            Request request = new Request.Builder()
                    .url(ApiUrls.getUrlByApiName("PHOTO_TO_PDF"))
                    .method("POST", requestBody)
                    .addHeader("x-ti-app-id", apiConfig.getAccessKey())
                    .addHeader("x-ti-secret-code", apiConfig.getSecretKey())
                    .addHeader("Content-Type", "application/json")
                    .build();

            Response response = client.newCall(request).execute();

            ObjectMapper mapper = new ObjectMapper();
            if (response.isSuccessful()) {
                JsonNode jsonResponse = mapper.readTree(response.body().byteStream());

                int code = jsonResponse.get("code").asInt();
                if (code == 200) {
                    try {
                        String filename = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + "(IMAGE_TO_PDF).pdf";
                        String FileUrl = AliOSSUtils.uploadFileToOSS(filename, Base64.getDecoder().decode(jsonResponse.get("result").asText()));
                        return this.insertFile(filename, userId, FileUrl) == 1 ? TextInResult.ok(FileUrl) :
                                TextInResult.fail(666, "存储文件失败");
                    } catch (Exception e) {
                        return TextInResult.fail(code, "上传文件到阿里云OSS失败");
                    }
                }
                String message = jsonResponse.get("message").asText();
                return TextInResult.fail(code, message);
            } else {
                return TextInResult.fail(response.code(), "请求失败");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int deleteHistoryFile(Long userId) {
        return textInMapper.deleteHistoryFile(userId);
    }

}